import { parse, type HTMLElement } from "node-html-parser";
import fs from "fs";
import pLimit from "p-limit";
import path from "path";
import cliProgress from "cli-progress";
// 引入封装
import { axiosInstance as axios, fileUtils } from "./axios.js";

//=============主函数=============
//用于启动爬虫

main();

async function main() {
  const { keywordsToProcess } = fileUtils.resumeCrawling();

  try {
    for (const keyword of keywordsToProcess) {
      console.log(`🔍 开始爬取 ${keyword} 相关图片`);
      await getImgsBykeyword(keyword);
      console.log(`✅ 爬取 ${keyword} 相关图片完成`);
      fileUtils.writeConfig({ lastProcessedKeyword: keyword });
    }
  } catch (error) {
    fileUtils.logError(error);
  }
}

//如何获取页面数据，总图片数，
//================== 【1】解析页面数据,获取图片url =======================
async function getImgUrlsBykeyword(keyword: string, page = 1) {
  const res = await axios({
    url: "https://www.zcool.com.cn/p1/search/image",
    method: "POST",
    headers: {
      "content-type": "application/json",
      "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
      url: `https://www.zcool.com.cn/search/content?recommendLevel=1&word=${encodeURIComponent(
        keyword
      )}`,
    },
    data: `{"cate_id":0,"city_id":0,"recommend_level":0,"sort":5,"word":"${keyword}","time":0,"p":${page},"ps":30}`,
  });
  const datas = res.data.datas;
  const total = res.data.total;
  console.log(`📸 第 ${page} 页图片`);
  return { datas, total };
}

async function getImgsBykeyword(keyword: string) {
  //第一页加载，先打印总共的图片数量
  const imgUrls: string[] = [];
  let currentPage = 1;

  let { datas, total } = await getImgUrlsBykeyword(keyword);
  console.log(`📸 总共 ${total} 张图片\n`);

  for (const data of datas) {
    if (data.id) {
      const imgUrl = data.url.split("?")[0] + "?imageMogr2/format";
      imgUrls.push(imgUrl);
    }
  }

  await downloadImgs(keyword, "image", imgUrls);

  while (currentPage < total / datas.length + 1) {
    currentPage++;
    let { datas } = await getImgUrlsBykeyword(keyword, currentPage);
    let newImgUrls: string[] = [];
    if (datas.length === 0) break;
    for (const data of datas) {
      if (data.id) {
        const imgUrl = data.url.split("?")[0] + "?imageMogr2/format";
        newImgUrls.push(imgUrl);
      }
    }
    await downloadImgs(keyword, "image", newImgUrls);
  }
}

// ===================== 【2】下载图片到本地 =====================
async function downloadImgWithRetry(
  imgUrl: string,
  filePath: string,
  retries = 3
) {
  // 如果文件已经存在，则直接返回
  if (fs.existsSync(filePath)) {
    return;
  }

  try {
    const res = await axios.get(imgUrl, {
      responseType: "arraybuffer",
    });
    fs.writeFileSync(filePath, Buffer.from(res.data));
  } catch (error) {
    if (retries > 0) {
      console.log(`⚠️ 图片下载失败，重试中...`);
      await new Promise((resolve) =>
        setTimeout(resolve, Math.random() * 1000 + 1000)
      );
      return downloadImgWithRetry(imgUrl, filePath, retries - 1);
    } else {
      fileUtils.logError(error);
    }
  }
}

async function downloadImgs(keyword: string, type: string, imgUrls: string[]) {
  console.log(`🔥 开始下载 ${imgUrls.length} 张图片`);
  const dir = path.resolve(fileUtils.outDirPath, keyword, type);
  fs.mkdirSync(dir, { recursive: true }); //确保目录存在
  const limit = pLimit(fileUtils.config.concurrency); // 限制下载并发

  // 初始化进度条
  const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.rect);
  progressBar.start(imgUrls.length, 0);

  const promises = imgUrls.map(async (imgUrl) => {
    const rowimgUrl = imgUrl.split("?")[0];
    const fileName = path.basename(rowimgUrl); // 取 imgUrl 最后 / 之后的字符串作为文件名

    return limit(async () => {
      const filePath = `${dir}/${fileName}`;
      await downloadImgWithRetry(imgUrl, filePath);
      progressBar.increment(); // 更新进度条
    });
  });

  await Promise.all(promises);
  progressBar.stop(); // 停止进度条
}
